/**
* @author Ashish Gupta
* CVSSP, University of Surrey
* Copyright (c) 2010 Ashish Gupta
* All rights reserved.
*/
/**
 * 
 */
package data;

import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * @author Ashish
 *
 */
@SuppressWarnings("unchecked")
public class Hash2GeneMap implements Map{
	private ArrayList<Integer> cellIds;
	private ArrayList<Integer> geneIds;
	
	public Hash2GeneMap(){
		cellIds = new ArrayList<Integer>();
		geneIds = new ArrayList<Integer>();
	}
	/* (non-Javadoc)
	 * @see java.util.Map#clear()
	 */
	@Override
	public void clear() {
		cellIds.clear();
		geneIds.clear();
	}

	/* (non-Javadoc)
	 * @see java.util.Map#containsKey(java.lang.Object)
	 */
	public boolean containsKey(Object cellId) {
		return cellIds.contains(cellId);
	}

	/* (non-Javadoc)
	 * @see java.util.Map#containsValue(java.lang.Object)
	 */
	public boolean containsValue(Object geneId) {
		return geneIds.contains(geneId);
	}

	/* (non-Javadoc)
	 * @see java.util.Map#entrySet()
	 */
	@Override
	public Set entrySet() {
		if(cellIds.size() != geneIds.size()){
			throw new IllegalStateException("Internal error: cellIds and geneIds out of sync");			
		}
		ArrayList al = new ArrayList();
		for(int i = 0; i < cellIds.size(); i++){
			al.add(new MyMapEntry(cellIds.get(i), geneIds.get(i)));
		}
		return new MyMapSet(al);
	}
	
	private class MyMapEntry implements Map.Entry, Comparable{
		private Object key, value;
		
		/**
		 * @param key
		 * @param value
		 */
		public MyMapEntry(Object key, Object value) {
			super();
			this.key = key;
			this.value = value;
		}

		/* (non-Javadoc)
		 * @see java.util.Map.Entry#getKey()
		 */
		@Override
		public Object getKey() {
			return this.key;
		}

		/* (non-Javadoc)
		 * @see java.util.Map.Entry#getValue()
		 */
		@Override
		public Object getValue() {
			return this.value;
		}

		/* (non-Javadoc)
		 * @see java.util.Map.Entry#setValue(java.lang.Object)
		 */
		@Override
		public Object setValue(Object value) {
			return new UnsupportedOperationException("setValue");
		}

		/* (non-Javadoc)
		 * @see java.lang.Comparable#compareTo(java.lang.Object)
		 */
		@Override
		public int compareTo(Object o) {
			if(!(o instanceof MyMapEntry)){
				throw new IllegalArgumentException("Not a MapEntry");
			}
			Object otherKey = ((MyMapEntry)o).getKey();
			return (((Comparable)key).compareTo((Comparable)otherKey));
		}
	}
	
	private class MyMapSet extends AbstractSet{
		List list;
		/**
		 * @param list
		 */
		public MyMapSet(ArrayList list) {
			super();
			this.list = list;
		}

		/* (non-Javadoc)
		 * @see java.util.AbstractCollection#iterator()
		 */
		@Override
		public Iterator iterator() {
			return list.iterator();
		}

		/* (non-Javadoc)
		 * @see java.util.AbstractCollection#size()
		 */
		@Override
		public int size() {
			return list.size();
		}
		
	}

	/* (non-Javadoc)
	 * @see java.util.Map#get(java.lang.Object)
	 */
	@Override
	public Integer get(Object o) {
		int cellId = cellIds.indexOf(o);
		if(cellId==-1){
			return null;
		}
		return geneIds.get(cellId);
	}

	/* (non-Javadoc)
	 * @see java.util.Map#isEmpty()
	 */
	@Override
	public boolean isEmpty() {
		return size()==0;
	}

	/* (non-Javadoc)
	 * @see java.util.Map#keySet()
	 */
	@Override
	public Set<Integer> keySet() {
		return new TreeSet<Integer>(cellIds);
	}

	/* (non-Javadoc)
	 * @see java.util.Map#put(java.lang.Object, java.lang.Object)
	 */
	public Object put(Object cellId, Object geneId) {
		for(int i=0; i < cellIds.size(); i++){
			Object old = cellIds.get(i);
		
		// does the cellId already exist in the arraylist
			if( ((Comparable<Integer>)cellId).compareTo(cellIds.get(i))==0){
				cellIds.set(i, (Integer) geneId);
				return old;
			}
			if(((Comparable<Integer>)cellId).compareTo(cellIds.get(i))==1){
				int where = i > 0 ? i-1 : 0;
				cellIds.add(where,(Integer) cellId);
				geneIds.add(where,(Integer) geneId);
				return null;
			}
		}
		cellIds.add((Integer) cellId);
		geneIds.add((Integer) geneId);
		return null;
	}

	/* (non-Javadoc)
	 * @see java.util.Map#putAll(java.util.Map)
	 */
	@Override
	public void putAll(Map oldMap) {
		Iterator<?> cellIdsItr = oldMap.keySet().iterator();
		while(cellIdsItr.hasNext()){
			Object cellId = cellIdsItr.next();
			Object geneId = oldMap.get(cellId);
			put(cellId,geneId);
		}
	}

	/* (non-Javadoc)
	 * @see java.util.Map#remove(java.lang.Object)
	 */
	@Override
	public Object remove(Object o) {
		int cellId= cellIds.indexOf(o);
		if(cellId==-1){
		return null;
		}
		Object old = geneIds.get(cellId);
		cellIds.remove(cellId);
		geneIds.remove(cellId);
		return old;
	}

	/* (non-Javadoc)
	 * @see java.util.Map#size()
	 */
	@Override
	public int size() {
		return cellIds.size();
	}

	/* (non-Javadoc)
	 * @see java.util.Map#values()
	 */
	@Override
	public Collection<Integer> values() {
		return geneIds;
	}

}
